//
//  QHPlayer.m
//  QHAudioConverterMan
//
//  Created by Anakin chen on 2021/4/13.
//

#import "QHPlayer.h"

#import <AVFoundation/AVFoundation.h>
#import <AudioUnit/AudioUnit.h>

#import "QHConfig.h"

@interface QHPlayer ()

@property (nonatomic) AUGraph auGraph;

@property (nonatomic) AUNode ioNode;
@property (nonatomic) AudioUnit ioUnit;

@end

@implementation QHPlayer

- (instancetype)init {
    self = [super init];
    if (self) {
        [self p_setup];
    }
    return self;
}

- (void)play {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        OSStatus status;
        status = AUGraphStart(self.auGraph);
    });
}

- (void)close {
    AUGraphClose(self.auGraph);
}

- (void)p_setup {
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    
    [self createAUGraph];
}

- (void)createAUGraph {
    OSStatus status;
    status = NewAUGraph(&_auGraph);
    [self addAUNode];
    status = AUGraphOpen(_auGraph);
    [self getAUsFromNodes];
    [self setAUProperties];
    [self makeAUConnects];
    CAShow(_auGraph);
    status = AUGraphInitialize(_auGraph);
}

- (void)addAUNode {
    OSStatus status;
    AudioComponentDescription ioDescription;
    bzero(&ioDescription, sizeof(ioDescription));
    ioDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
    ioDescription.componentType = kAudioUnitType_Output;
    ioDescription.componentSubType = kAudioUnitSubType_RemoteIO;
    
    status = AUGraphAddNode(_auGraph, &ioDescription, &_ioNode);
}

- (void)getAUsFromNodes {
    OSStatus status;
    status = AUGraphNodeInfo(_auGraph, _ioNode, NULL, &_ioUnit);
}

- (void)setAUProperties {
    OSStatus status;
    AudioStreamBasicDescription asbd = [[QHConfig sharestance] createPCMMonoAudioSBDes];
    status = AudioUnitSetProperty(_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &asbd, sizeof(asbd));
    AudioStreamBasicDescription asbd1 = [[QHConfig sharestance] createPCMMonoAudioSBDes];
    status = AudioUnitSetProperty(_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &asbd1, sizeof(asbd1));
}

- (void)makeAUConnects {
    OSStatus status;
    AURenderCallbackStruct finalRenderProc;
    finalRenderProc.inputProc = &renderCallback;
    finalRenderProc.inputProcRefCon = (__bridge void *)self;
    // 1
    status = AUGraphSetNodeInputCallback(_auGraph, _ioNode, 0, &finalRenderProc);
}

#pragma mark - Callback

static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
    return play(inRefCon, ioData);
}

static OSStatus play(void *inRefCon, AudioBufferList *ioData) {
    OSStatus result = noErr;
    __unsafe_unretained QHPlayer *thisSelf = (__bridge QHPlayer *)inRefCon;
    
//    AudioBufferList *bufList = [thisSelf.delegate renderPlay:thisSelf];
//    if (bufList != NULL) {
//        int s = sizeof(AudioBufferList) + (bufList->mNumberBuffers - 1) * sizeof(AudioBuffer);
//        memcpy(ioData, bufList, s);
//    }
    
    NSData *data = [thisSelf.delegate renderPlay2:thisSelf size:ioData->mBuffers[0].mDataByteSize];
    if (data) {
        ioData->mBuffers[0].mData = (void *)data.bytes;
    }
    
    return result;
}

@end
